﻿Imports System.Collections.Generic

Public Class MainForm

#Region "Samplizer"
    Private Class ComboItem
        Public Name As String
        Public Query As Reflection.MethodInfo
        Public Overrides Function ToString() As String
            Return Name
        End Function
    End Class

    Private Class SampleAttribute
        Inherits Attribute
        Public Name As String
        Public Sub New(ByVal sampleName As String)
            Name = sampleName
        End Sub
    End Class

    Private Sub MainForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim methods = GetType(MainForm).GetMethods(Reflection.BindingFlags.Instance Or _
                                                 Reflection.BindingFlags.InvokeMethod Or _
                                                 Reflection.BindingFlags.NonPublic Or _
                                                 Reflection.BindingFlags.Public)
        For Each mthd In methods
            Dim attributes = mthd.GetCustomAttributes(GetType(SampleAttribute), False)
            If attributes IsNot Nothing AndAlso attributes.Length > 0 Then
                Me.cboSamples.Items.Add(New ComboItem With {.Name = CType(attributes(0), SampleAttribute).Name, .Query = mthd})
            End If
        Next
    End Sub

    Private Sub btnRun_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRun.Click
        Dim ci = TryCast(Me.cboSamples.SelectedItem, ComboItem)
        If ci Is Nothing Then Return
        mOutStream = New IO.StringWriter
        ci.Query.Invoke(Me, Nothing)
        mOutStream.Flush()
        Me.txtOutput.Text = mOutStream.ToString
        mOutStream.Close()
        mOutStream = Nothing
    End Sub
#End Region

    Private mOutStream As IO.StringWriter

    Private mCustomerNameLength As Integer = 5
    Private mProductToFind As String = "Milk"

    <Sample("Old Style Query")> _
    Private Sub OldStyleQuery()
        Dim customers As Customer() = BuildCustomers()

        Dim results As New List(Of SearchResult)
        'Dim matcher As New SearchForProduct(mProductToFind)
        For Each c As Customer In customers
            If c.FirstName.Length >= mCustomerNameLength Then
                'Dim orders = Array.FindAll(c.Orders, AddressOf matcher.ProductMatch)
                Dim orders = Array.FindAll(c.Orders, Function(o As Order) o.Product = mProductToFind)
                Dim cr As New SearchResult
                cr.Customer = c.FirstName & " " & c.LastName
                For Each o As Order In orders
                    cr.Quantity += o.Quantity
                    cr.Count += 1
                Next
                results.Add(cr)
            End If
        Next

        'results.Sort(New Comparison(Of SearchResult)(AddressOf CompareSearchResults))
        results.Sort(New Comparison(Of SearchResult)(Function(result1 As SearchResult, result2 As SearchResult) String.Compare(result1.Customer, result2.Customer)))

        ObjectDumper.Write(results, log:=mOutStream)
    End Sub

    Private Function CompareSearchResults(ByVal result1 As SearchResult, ByVal result2 As SearchResult) As Integer
        Return String.Compare(result1.Customer, result2.Customer)
    End Function

    <Sample("Basic Linq Query (From Only)")> _
    Private Sub LinqQueryFromOnly()
        Dim customers = BuildCustomers()

        Dim results = From c In customers, o In c.Orders

        ObjectDumper.Write(results, 1, log:=mOutStream)
    End Sub

    <Sample("Basic Linq Query (With Select)")> _
    Private Sub LinqQueryWithSelect()
        Dim customers = BuildCustomers()

        Dim results = From c In customers, o In c.Orders _
                      Select c.FirstName, c.LastName, o.Product, o.Quantity

        ObjectDumper.Write(results, log:=mOutStream)

    End Sub

    <Sample("Linq Query (with Where)")> _
    Private Sub LinqQueryWithWhere()
        Dim customers = BuildCustomers()


        Dim results = From c In customers, o In c.Orders _
                      Where c.FirstName.Length >= mCustomerNameLength And o.Product = Me.mProductToFind _
                      Select c.FirstName, c.LastName, o.Product, o.Quantity

        'Alternatively.....
        'Dim results = From c In customers, o In c.Orders _
        '              Select c.FirstName, c.LastName, o.Product, o.Quantity _
        '              Where(FirstName.Length >= mCustomerNameLength And Product = Me.mProductToFind)


        ObjectDumper.Write(results, log:=mOutStream)

    End Sub

    <Sample("Linq Query (with Group By)")> _
    Private Sub LinqQueryWithGrouping()
        Dim customers = BuildCustomers()

        Dim results = From c In customers, o In c.Orders _
                      Group By c Into oGroup = Group, avg = Average(o.Quantity) _
                      Select c.FirstName, c.LastName, avg

        ObjectDumper.Write(results, log:=mOutStream)

    End Sub

    <Sample("Linq Query (with Group By and Where)")> _
    Private Sub LinqQueryWithGroupingAndWhere()
        Dim customers = BuildCustomers()

        Dim results = From c In customers, o In c.Orders _
                      Where c.FirstName.Length >= mCustomerNameLength And o.Product = Me.mProductToFind _
                      Group By c Into avg = Average(o.Quantity) _
                      Select c.FirstName, c.LastName, avg

        ObjectDumper.Write(results, log:=mOutStream)

    End Sub

    <Sample("Linq Query (with projections)")> _
    Private Sub LinqQueryWithProjections()
        Dim customers = BuildCustomers()

        Dim results = From c In customers, o In c.Orders _
                      Where c.FirstName.Length >= mCustomerNameLength And _
                            o.Product = Me.mProductToFind _
                      Group By c Into avg = Average(o.Quantity) _
                      Select New With {.Name = c.FirstName & " " & c.LastName, .AverageMilkOrder = avg}


        ObjectDumper.Write(results, log:=mOutStream)

    End Sub

    <Sample("Final Linq Query")> _
    Private Sub FinalLinqQuery()
        Dim customers = BuildCustomers()

        Dim results = From c In customers, o In c.Orders _
                      Order By c.FirstName _
                      Where c.FirstName.Length >= mCustomerNameLength And _
                            o.Product = Me.mProductToFind _
                      Group By c Into avg = Average(o.Quantity) _
                      Select New With {.Name = c.FirstName & " " & c.LastName, .AverageMilkOrder = avg}

        ObjectDumper.Write(results, log:=mOutStream)

    End Sub

    <Sample("C# Linq Query")> _
    Private Sub CLinqQuery()
        Dim customers = BuildCustomers()
        Dim results = CLinq.CustomerQueries.FinalQuery(customers)
        ObjectDumper.Write(results, log:=mOutStream)
    End Sub












    Private Function BuildCustomers() As Customer()
        Return New Customer() {New Customer() With {.FirstName = "Bob", .LastName = "Jones", .Email = "bob@random.com", .Phone = "+61 010 010 010", .Orders = New Order() {New Order With {.Product = "Milk", .Quantity = 2}, New Order With {.Product = "Cereal", .Quantity = 10}, New Order With {.Product = "Milk", .Quantity = 5}}}, _
                               New Customer() With {.FirstName = "Alastair", .LastName = "Kelly", .Email = "al@random.com", .Phone = "+61 010 010 010", .Orders = New Order() {New Order With {.Product = "Milk", .Quantity = 9}, New Order With {.Product = "Bread", .Quantity = 7}, New Order With {.Product = "Milk", .Quantity = 6}, New Order With {.Product = "Pears", .Quantity = 8}}}, _
                               New Customer() With {.FirstName = "Jenny", .LastName = "Jackson", .Email = "jenny@random.com", .Phone = "+61 010 010 010", .Orders = New Order() {New Order With {.Product = "Eggs", .Quantity = 15}, New Order With {.Product = "Apples", .Quantity = 4}, New Order With {.Product = "Milk", .Quantity = 1}}}, _
                               New Customer() With {.FirstName = "Crystal", .LastName = "Major", .Email = "cm@random.com", .Phone = "+61 010 010 010", .Orders = New Order() {New Order With {.Product = "Eggs", .Quantity = 15}, New Order With {.Product = "Apples", .Quantity = 4}, New Order With {.Product = "Milk", .Quantity = 7}}}}
    End Function

    Private Class SearchForProduct
        Private mProduct As String
        Public Sub New(ByVal searchProduct As String)
            mProduct = searchProduct
        End Sub

        Public Function ProductMatch(ByVal queryOrder As Order) As Boolean
            Return String.Compare(queryOrder.Product, mProduct, True) = 0
        End Function
    End Class


    Private Class SearchResult

        Private mCustomer As String

        Private mQuantity As Integer

        Private mCount As Integer

        Public ReadOnly Property Average() As Double
            Get
                If mCount = 0 Then Return 0
                Return mQuantity / mCount
            End Get
        End Property

        Public Property Count() As Integer
            Get
                Return mCount
            End Get
            Set(ByVal value As Integer)
                mCount = value
            End Set
        End Property


        Public Property Quantity() As Integer
            Get
                Return mQuantity
            End Get
            Set(ByVal value As Integer)
                mQuantity = value
            End Set
        End Property

        Public Property Customer() As String
            Get
                Return mCustomer
            End Get
            Set(ByVal value As String)
                mCustomer = value
            End Set
        End Property

    End Class

End Class



